package com.hnas.trade.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hnas.common.outdto.SearchRecgPayInfoForm;
import com.hnas.common.outdto.SearchRecgPayInfoReceive;
import com.hnas.common.util.CommonReturn;
import com.hnas.common.util.CommonUtils;
import com.hnas.common.util.PostServerInfoGet;
import com.hnas.common.util.ResultCode;
import com.hnas.core.app_common.util.DTOResult;
import com.hnas.core.util.DateUtil;
import com.hnas.eCard.dao.CommoditDetailReDao;
import com.hnas.eCard.dao.CommoditOrderDetailDao;
import com.hnas.eCard.domain.ECardCommonFinalValue;
import com.hnas.eCard.orm.CommoditDetailRe;
import com.hnas.eCard.orm.CommoditOrderDetail;
import com.hnas.eCard.service.dto.DTOCommoditDetail;
import com.hnas.eastsquare.dao.SediBalanceChangeRecordDao;
import com.hnas.eastsquare.dao.SediToBalanceRecordDao;
import com.hnas.eastsquare.dao.SedimentaryBalanceDao;
import com.hnas.eastsquare.orm.SediBalanceChangeRecord;
import com.hnas.eastsquare.service.SedimentaryBalanceService;
import com.hnas.eastsquare.util.JedisPoolUtil;
import com.hnas.trade.dao.OrderDao;
import com.hnas.trade.dao.OrderDetailDao;
import com.hnas.trade.dao.TradeRecordDao;
import com.hnas.trade.dao.TradeRecordDetailDao;
import com.hnas.trade.domain.DetailType;
import com.hnas.trade.domain.OrderStatus;
import com.hnas.trade.dto.DTOOrder;
import com.hnas.trade.dto.DTOOrderDetail;
import com.hnas.trade.dto.DTOPosOrder;
import com.hnas.trade.dto.DTOTradeRecord;
import com.hnas.trade.dto.GetOrderInfoByQRCodeReturn;
import com.hnas.trade.dto.intf.CreateOrderDetailBean;
import com.hnas.trade.mapper.OrderMapper;
import com.hnas.trade.orm.Order;
import com.hnas.trade.orm.OrderDetail;
import com.hnas.trade.orm.TradeRecord;
import com.hnas.trade.orm.TradeRecordDetail;

import redis.clients.jedis.Jedis;

@Component("orderService")
// @Transactional(isolation=Isolation.READ_COMMITTED,readOnly=false,propagation=Propagation.REQUIRED,value="transactionManagerHnt")
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public class OrderServiceImpl implements OrderService {

	private static Log logger = LogFactory.getLog(OrderServiceImpl.class);

	@Autowired
	private PostServerInfoGet postServerInfoGet;

	@Autowired
	private OrderDao orderDao;

	private static ObjectMapper objectMapper = new ObjectMapper();

	@Autowired
	private TradeRecordDao tradeRecordDao;

	@Autowired
	private OrderDetailDao orderDetailDao;

	@Autowired
	private TradeRecordDetailDao tradeRecordDetailDao;

	@Autowired
	private SedimentaryBalanceDao sedimentaryBalanceDao;
	@Autowired
	private SediToBalanceRecordDao sediToBalanceRecordDao;
	@Autowired
	private SediBalanceChangeRecordDao sediBalanceChangeRecordDao;
	@Autowired
	private SedimentaryBalanceService sedimentaryBalanceService;
	@Autowired
	private CommoditOrderDetailDao commoditOrderDetailDao;
	@Autowired
	private CommoditDetailReDao commoditDetailReDao;
//	@Autowired
//	private JedisUtil jedisUtil;
	@Autowired
	private JedisPoolUtil jedisPoolUtil;

	@Override
	public Order saveOrUpdate(DTOOrder dto) throws Exception {
		return this.orderDao.saveOrUpdate(dto);
	}
	
	@Override
	public DTOOrder getByOrderNo(String orderNo) {
		return this.orderDao.getByOrderNo(orderNo);
	}

	@Override
	public String getOrderInfoByQRCode(String qrCode) {
		DTOResult dtoResult = new DTOResult();
		GetOrderInfoByQRCodeReturn dtO = new GetOrderInfoByQRCodeReturn();
		try {
			Order order = this.orderDao.findByQRCode(qrCode);
			if (null != order) {
				if (OrderStatus.Payed.getStatus().equals(order.getOrderStatus())) {// 若成功，生成一条新的交易记录
					// DTOTradeRecord dRecord =
					// OrderMapper.getInstance().mapToDTOTradeRecord(order);
					// if(null!=dRecord){
					// dRecord.setId(CommonUtils.getUUID());
					// }
					// tradeRecordDao.saveOrUpdate(dRecord);
					List<TradeRecordDetail> vipDetails = this.tradeRecordDetailDao
							.getByOrderNoAndType(order.getOrderNo(), DetailType.VIP.getKey());
					TradeRecordDetail vipDetail = null;
					if (vipDetails != null && vipDetails.size() > 0) {
						vipDetail = vipDetails.get(0);
					}
					List<TradeRecordDetail> couponDetails = this.tradeRecordDetailDao
							.getByOrderNoAndType(order.getOrderNo(), DetailType.COUPON.getKey());
					JSONObject detailObj = createPosReturnJson(vipDetail, couponDetails);
					dtO = OrderMapper.getInstance().valueToGetOrderInfoReturn(order);
					dtO.setOrder_detail(objectMapper.writeValueAsString(detailObj));

					// this.sedimentaryBalanceService.updateByOrderNo(order.getOrderNo(),
					// 1000*100L);
				} else {
					dtO = OrderMapper.getInstance().valueToGetOrderInfoReturn(order);
				}
				dtoResult.setResultCode(ResultCode.SUCCESS);
				dtoResult.setResultMsg(ResultCode.getResultValue(ResultCode.SUCCESS));
				dtoResult.setResultData(objectMapper.writeValueAsString(dtO));
				return objectMapper.writeValueAsString(dtoResult);
			} else {
				dtoResult.setResultCode(ResultCode.ERROR_047);
				dtoResult.setResultMsg(ResultCode.getResultValue(ResultCode.ERROR_047));
				return objectMapper.writeValueAsString(dtoResult);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private JSONObject createPosReturnJson(TradeRecordDetail vipDetail, List<TradeRecordDetail> couponDetails) {
		JSONObject detailObj = new JSONObject();
		JSONObject vip = new JSONObject();
		if (vipDetail != null) {
			vip.put("product_id", vipDetail.getRelateId());
			vip.put("product_name", vipDetail.getProductName());
			vip.put("discount_type", vipDetail.getDiscountType());
			vip.put("discount_value", vipDetail.getDiscountValue());
			vip.put("discount_amount", vipDetail.getDiscountAmount());
		}
		detailObj.put("vip", vip);
		JSONArray coupons = new JSONArray();
		for (TradeRecordDetail od : couponDetails) {
			JSONObject coupon = new JSONObject();
			coupon.put("coupon_id", od.getRelateId());
			coupon.put("coupon_type_name", od.getCouponTypeName());
			coupon.put("discount_type", od.getDiscountType());
			coupon.put("discount_value", od.getDiscountValue());
			coupon.put("discount_amount", od.getDiscountAmount());
			coupons.add(coupon);
		}
		detailObj.put("coupons", coupons);
		return detailObj;
	}

	@Override
	public DTOOrder getBySwiftNumber(String swiftNumber) {
		return this.orderDao.getBySwiftNumber(swiftNumber);
	}

	@Override
	public DTOPosOrder createPosOrder(DTOOrder dto, DTOOrderDetail mrch, DTOOrderDetail vip,
			List<DTOOrderDetail> couponList) throws Exception {
		DTOPosOrder posOrder = new DTOPosOrder();
		Order order = this.saveOrUpdate(dto);
		posOrder.setOrder(order);
		if (mrch != null) {
			OrderDetail orderDetail = this.orderDetailDao.saveOrUpdate(mrch);
			posOrder.setMrch(orderDetail);
		}
		if (vip != null) {
			OrderDetail orderDetail = this.orderDetailDao.saveOrUpdate(vip);
			posOrder.setVip(orderDetail);
		}
		List<OrderDetail> newCouponList = new ArrayList<OrderDetail>();
		if (null != couponList && couponList.size() > 0) {
			for (DTOOrderDetail detail : couponList) {
				OrderDetail orderDetail = this.orderDetailDao.saveOrUpdate(detail);
				newCouponList.add(orderDetail);
			}
		}

		posOrder.setCoupons(newCouponList);
		return posOrder;
	}

	@Override
	public void updateStatusByOrderNo(String orderNo, String status) {
		orderDao.updateOrderStatus(orderNo, status);
	}

	@Override
	public String recharge(String orderNo) throws JsonProcessingException {
		DTOResult dtoResult = new DTOResult();
		// 根据orderNo获取订单
		DTOOrder orderDto = this.orderDao.getByOrderNo(orderNo);
		if (null == orderDto) {
			dtoResult.setResultCode(ResultCode.ERROR_047);
			dtoResult.setResultMsg(ResultCode.getResultValue(ResultCode.ERROR_047));
			return objectMapper.writeValueAsString(dtoResult);
		}
		try {
			// 1，调用查询充值交易订单信息
			SearchRecgPayInfoForm form = new SearchRecgPayInfoForm();
			form.setSwiftNumber(orderDto.getSwiftNumber());
			CommonReturn commonReturn = postServerInfoGet.searchRecgPayInfo(form);
			String resultCode = commonReturn.getResultCode();
			if (ResultCode.FAIL.equals(resultCode)) {
				dtoResult.setResultCode(ResultCode.FAIL);
				dtoResult.setResultMsg(ResultCode.getResultValue(ResultCode.FAIL));
				return objectMapper.writeValueAsString(dtoResult);
			} else {
				SearchRecgPayInfoReceive searchRecgPayInfoReceive = (SearchRecgPayInfoReceive) commonReturn
						.getResultData();
				if ("1" == searchRecgPayInfoReceive.getRechargeStatus()) {// 充值成功
					// orderDao.updateOrderStatus(orderNo,
					// OrderStatus.Payed.getStatus());
					orderDto.setTradeSno(searchRecgPayInfoReceive.getRechargeNum());
					orderDto.setOrderStatus(OrderStatus.Payed.getStatus());
					orderDto.setUpdateTime(DateUtil.dateTimeToString(new Date()));
					orderDao.saveOrUpdate(orderDto);

					DTOTradeRecord dtoTradeRecord = new DTOTradeRecord();
					BeanUtils.copyProperties(orderDto, dtoTradeRecord, new String[] { "id" });
					dtoTradeRecord.setId(CommonUtils.getUUID());
					TradeRecord tradeRecord = this.tradeRecordDao.saveOrUpdate(dtoTradeRecord);
					if (tradeRecord == null) {
						// 存储交易记录失败
						dtoResult.setResultCode(ResultCode.ERROR_039);
						dtoResult.setResultMsg(ResultCode.getResultValue(ResultCode.ERROR_039));
						return objectMapper.writeValueAsString(dtoResult);
					}
					dtoResult.setResultCode(ResultCode.SUCCESS);
					dtoResult.setResultMsg(ResultCode.getResultValue(ResultCode.SUCCESS));
					return objectMapper.writeValueAsString(dtoResult);
				}

			}

		} catch (Exception e) {
			dtoResult.setResultCode(ResultCode.FAIL);
			dtoResult.setResultMsg(ResultCode.getResultValue(ResultCode.FAIL));
			return objectMapper.writeValueAsString(dtoResult);
		}
		dtoResult.setResultCode(ResultCode.FAIL);
		dtoResult.setResultMsg(ResultCode.getResultValue(ResultCode.FAIL));
		return objectMapper.writeValueAsString(dtoResult);
	}

	@Override
	public void updateOrderStatus(String orderNo, String status) {
		orderDao.updateOrderStatus(orderNo, status);
	}

	@Override
	public Order saveQrcode(DTOOrder orderDto, List<CreateOrderDetailBean> beans) throws Exception {
		Order order = this.saveOrUpdate(orderDto);
		if (beans.size() > 0) {
			for (CreateOrderDetailBean bean : beans) {
				DTOOrderDetail orderDetail = new DTOOrderDetail();
				orderDetail.setId(CommonUtils.getUUID());
				orderDetail.setCreateTime(DateUtil.dateTimeToString(new Date()));
				orderDetail.setUpdateTime(DateUtil.dateTimeToString(new Date()));
				orderDetail.setOrderNo(order.getOrderNo());
				orderDetail.setRelateId(bean.getRaletedId());
				orderDetail.setIsDeleted(false);
				orderDetail.setDiscountType(bean.getDiscountType());
				orderDetail.setDiscountAmount(bean.getDiscountAmount() + "");
				orderDetail.setDiscountValue(bean.getDiscountValue());
				orderDetail.setProductName(bean.getProductName());
				orderDetail.setActivityItemType(bean.getActivityItemType());
				if (DetailType.COUPON.getKey().equals(bean.getType())) {
					orderDetail.setType(DetailType.COUPON.getKey());
					orderDetail.setCouponTypeName(bean.getCouponName());
					orderDetail.setProductName(bean.getCouponName());
					orderDetailDao.saveOrUpdate(orderDetail);
				} else if (DetailType.VIP.getKey().equals(bean.getType())) {
					orderDetail.setType(DetailType.VIP.getKey());
					orderDetailDao.saveOrUpdate(orderDetail);
				} else if (DetailType.MrchDiscount.getKey().equals(bean.getType())) {
					orderDetail.setType(DetailType.MrchDiscount.getKey());
					orderDetailDao.saveOrUpdate(orderDetail);
				} else if (DetailType.EmpDiscount.getKey().equals(bean.getType())) {
					orderDetail.setType(DetailType.EmpDiscount.getKey());
					orderDetailDao.saveOrUpdate(orderDetail);
				} else if (DetailType.ActivityDiscount.getKey().equals(bean.getType())) {
					orderDetail.setType(DetailType.ActivityDiscount.getKey());
					orderDetailDao.saveOrUpdate(orderDetail);
				}

			}
			// 修改代金券状态为使用中,由于跨库不能与存订单时候进行修改
		}
		return order;
	}

	@Override
	public Order updateOrder(DTOOrder order, String status) throws Exception {
		// 修改订单
		order.setOrderStatus(status);
		order.setUpdateTime(DateUtil.dateTimeToString(new Date()));
		orderDao.saveOrUpdate(order);
		Order o = new Order();
		BeanUtils.copyProperties(order, o);
		return o;
	}

	@Override
	public List<Order> getEastSquarList(String date) {
		return this.orderDao.getEastSquarList(date);
	}

	@Override
	public int getEastSquareCount(String date) {
		return this.orderDao.getEastSquarCount(date);
	}

	@Override
	public String createEastSquareOrder(DTOOrder dto,DTOOrderDetail orderDetail, SediBalanceChangeRecord changeRecord) {
//		Jedis jedis = jedisUtil.getJedis();
		Jedis jedis = jedisPoolUtil.getJedis();
		Long derateAmount = 0L;
		Long discountAmt = 0L;

		if (changeRecord == null) {
			logger.info("orderNo:" + dto.getOrderNo() + ",数据库保存订单记录前：笔数：" + jedis.get("eastSquareCount") + ",减免总金额："
					+ jedis.get("eastSquareAmount") + "沉淀金额：" + jedis.get("sedimentary") + "余额："
					+ jedis.get("balance"));
			Order order = this.orderDao.saveOrUpdate(dto);
			if (order == null) {
				// 订单创建失败（返回）
				logger.info("orderNo:" + dto.getOrderNo() + ",数据库保存订单记录失败：笔数：" + jedis.get("eastSquareCount")
						+ ",减免总金额：" + jedis.get("eastSquareAmount") + "沉淀金额：" + jedis.get("sedimentary") + "余额："
						+ jedis.get("balance"));
				jedis.decrBy("eastSquareCount", 1);
				return ResultCode.ERROR_058;
			}
			return ResultCode.SUCCESS;
		}
		// 先减1%
		try {
			logger.info("orderNo:" + dto.getOrderNo() + ",数据库保存订单记录前：笔数：" + jedis.get("eastSquareCount") + ",减免总金额："
					+ jedis.get("eastSquareAmount") + "沉淀金额：" + jedis.get("sedimentary") + "余额："
					+ jedis.get("balance"));
			Order order = this.orderDao.saveOrUpdate(dto);
			if (order == null) {
				// 订单创建失败（返回）
				logger.info("orderNo:" + dto.getOrderNo() + ",数据库保存订单记录失败：笔数：" + jedis.get("eastSquareCount")
						+ ",减免总金额：" + jedis.get("eastSquareAmount") + "沉淀金额：" + jedis.get("sedimentary") + "余额："
						+ jedis.get("balance"));
				jedis.decrBy("eastSquareCount", 1);
				return ResultCode.ERROR_058;
			}
			//保存 订单详情
			if(orderDetail != null) this.orderDetailDao.saveOrUpdate(orderDetail);
			derateAmount = changeRecord.getBalanceChange();
			discountAmt = changeRecord.getSedimentaryChange();

			jedis.decrBy("balance", derateAmount);// 可以减免
			jedis.incrBy("sedimentary", discountAmt);// 沉淀池要加
			jedis.incrBy("eastSquareAmount", derateAmount);

			SediBalanceChangeRecord saveOrUpdate = this.sediBalanceChangeRecordDao.saveOrUpdate(changeRecord);
			if (saveOrUpdate == null) {
				logger.info("orderNo:" + dto.getOrderNo() + ",保存改变记录失败：笔数：" + jedis.get("eastSquareCount") + ",减免总金额："
						+ jedis.get("eastSquareAmount") + "沉淀金额：" + jedis.get("sedimentary") + "余额："
						+ jedis.get("balance"));
				return ResultCode.ERROR_137;
			}

			logger.info("orderNo:" + dto.getOrderNo() + ",订单创建成功：笔数：" + jedis.get("eastSquareCount") + ",减免总金额："
					+ jedis.get("eastSquareAmount") + "沉淀金额：" + jedis.get("sedimentary") + "余额："
					+ jedis.get("balance"));
			return ResultCode.SUCCESS;
		} catch (Exception e) {
			e.printStackTrace();
			jedis.incrBy("balance", derateAmount);
			jedis.decrBy("sedimentary", discountAmt);
			jedis.decrBy("eastSquareAmount", derateAmount);
			logger.info("创建订单保存东方广场交易记录异常，orderNo:" + dto.getOrderNo() + "," + e.getMessage() + ",笔数:"
					+ jedis.get("eastSquareCount") + ",减免总金额：" + jedis.get("eastSquareAmount") + "沉淀金额："
					+ jedis.get("sedimentary") + "余额：" + jedis.get("balance"));
			// 返回订单创建失败信息
			dto.setIsDeleted(true);// 将订单状态改为假删除
			this.orderDao.saveOrUpdate(dto);
			return ResultCode.ERROR_058;
		} finally {// 最后关闭redis
//			jedisUtil.closeJedis(jedis);
			if(jedis != null) jedis.close();
		}
	}

	@Override
	public int getCountByActivity(String mrchId, String termNo, String id, String dateStr) {
		return this.orderDao.getCountByActivity(mrchId, termNo, id, dateStr);
	}

	@Override
	public int getCountByAccno(String accno, String activityId,String itemId, String dateStr) {
		return this.orderDao.getCountByAccno(accno, activityId, itemId, dateStr);
	}

	@Override
	public List<DTOOrder> listAccountOrder(String accId, String cardNo) {
		return this.orderDao.listAccountOrder(accId, cardNo);
	}

	@Override
	public Order updateOrderSaveTradeRecord(DTOOrder dto) throws Exception {
		Order order = this.orderDao.saveOrUpdate(dto);
		DTOTradeRecord tradeRecord = new DTOTradeRecord();
		BeanUtils.copyProperties(order, tradeRecord, new String[]{"id"});
		tradeRecord.setId(CommonUtils.getUUID());
		this.tradeRecordDao.saveOrUpdate(tradeRecord);
		return order;
	}

	@Override
	public boolean createCommoditOrder(DTOOrder orderDto, List<DTOCommoditDetail> detailList) throws Exception{
		boolean res = true;
		Order order = this.orderDao.saveOrUpdate(orderDto);
		if(order == null) res = false;
		CommoditOrderDetail commoditOrderDetail = new CommoditOrderDetail();
		commoditOrderDetail.setId(CommonUtils.getUUID());
		commoditOrderDetail.setState(ECardCommonFinalValue.COMMODIT_ORDER_INIT);
		commoditOrderDetail.setOrderNo(orderDto.getOrderNo());
		CommoditOrderDetail detail = this.commoditOrderDetailDao.saveOrUpdate(commoditOrderDetail);
		if(detail == null) res = false;
		for(DTOCommoditDetail d : detailList) {
			CommoditDetailRe re = new CommoditDetailRe();
			re.setCommoditId(d.getId());
			re.setCount(d.getCommoditNum());
			re.setId(CommonUtils.getUUID());
			re.setOrderNo(orderDto.getOrderNo());
			CommoditDetailRe saveOrUpdate = this.commoditDetailReDao.saveOrUpdate(re);
			res = (res&&(saveOrUpdate != null));
		}
		return res;
	}

}
